package com.zzl.finance.data.util;

import org.springframework.util.ObjectUtils;

import javax.validation.constraints.NotNull;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.TimeZone;

/**
 * 日期工具类
 */
@SuppressWarnings("unused")
public class DateUtils {

    public static final int ONE_SECOND = 1000;
    /**
     * 60 * ONE_SECOND
     */
    public static final int ONE_MINUTE = 60000;
    /**
     * 60 * ONE_MINUTE
     */
    public static final int ONE_HOUR = 3600000;
    /**
     * 24 * ONE_HOUR
     */
    public static final int ONE_DAY = 86400000;
    public static final TimeZone TZ_SHANGHAI = TimeZone.getTimeZone("Asia/Shanghai");
    public static final String DF_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String DF_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private DateUtils() {
    }

    /**
     * 当前时间 加 天数
     *
     * @param days 增加天数
     * @return 截至日期的 23:59:59
     */
    public static Date dateAddDaysAll(Integer days) {
        try {
            DateFormat dateFormat = new SimpleDateFormat(DF_YYYY_MM_DD);
            dateFormat.setTimeZone(TZ_SHANGHAI);
            String now = dateFormat.format(new Date());
            Date date = addDays(dateFormat.parse(now), days + 1);
            return addSeconds(date, -1);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 日期字符串格式化
     *
     * @param dateStr  目标日期字符串
     * @param format   目标字符串的格式
     * @param toFormat 格式化后的格式
     * @return 格式化的字符串
     */
    public static String dateStringFormat(String dateStr, String format, String toFormat) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        SimpleDateFormat toSdf = new SimpleDateFormat(toFormat);
        try {
            return toSdf.format(sdf.parse(dateStr));
        } catch (ParseException e) {
            printStackTrace(e);
        }
        return "";
    }

    private static void printStackTrace(Exception e) {
        e.printStackTrace();
    }

    /**
     * 日期格式化，亚洲上海时区
     *
     * @param date   目标日期对象
     * @param format 格式
     * @return 格式化的字符串
     */
    public static String dateFormat(Date date, String format) {
        if (ObjectUtils.isEmpty(date)) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        sdf.setTimeZone(TZ_SHANGHAI);
        return sdf.format(date);
    }

    /**
     * date之后nextDay天的日期
     *
     * @param date    目标日期对象
     * @param nextDay 后多少天
     * @return 日期
     */
    public static Date nextSomeDay(Date date, int nextDay) {
        return new Date(date.getTime() + nextDay * ONE_DAY);
    }

    /**
     * 字符串转化成日期对象
     *
     * @param dateStr 日期字符串
     * @param format  格式
     * @return 日期对象
     */
    public static Date string2Date(String dateStr, String format) {
        DateFormat df = new SimpleDateFormat(format);
        try {
            TimeZone shanghai = TimeZone.getTimeZone("Asia/Shanghai");
            df.setTimeZone(shanghai);
            return df.parse(dateStr);
        } catch (ParseException e) {
            printStackTrace(e);
        }
        return null;
    }

    /**
     * LocalDate转Date
     *
     * @param localDate 目标对象
     * @return Date对象
     */
    public static Date localDate2Date(LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * Date转LocalDate
     *
     * @param date 目标对象
     * @return LocalDate对象
     */
    public static LocalDate date2LocalDate(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * LocalDateTime转Date
     *
     * @param localDateTime 目标对象
     * @return Date对象
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        if (null == localDateTime) {
            return null;
        }
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Date转LocalDateTime
     *
     * @param date 目标对象
     * @return LocalDate对象
     */
    public static LocalDateTime date2LocalDateTime(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 返回两个Date对象之间的天数，左包含右不包含
     *
     * @param dateStart 其实时间
     * @param dateEnd   结束时间
     * @return 相差天数
     */
    public static long between(@NotNull Date dateStart, @NotNull Date dateEnd) {
        LocalDate localDateStart = date2LocalDate(dateStart);
        LocalDate localDateEnd = date2LocalDate(dateEnd);
        return ChronoUnit.DAYS.between(localDateStart, localDateEnd);
    }

    /**
     * date加amount秒
     *
     * @param date   目标日期
     * @param amount 增加秒数
     * @return 计算后日期
     */
    public static Date addSeconds(Date date, int amount) {
        return org.apache.commons.lang.time.DateUtils.addSeconds(date, amount);
    }

    /**
     * date加amount天
     *
     * @param date   目标日期
     * @param amount 增加天数
     * @return 计算后日期
     */
    public static Date addDays(Date date, int amount) {
        return org.apache.commons.lang.time.DateUtils.addDays(date, amount);
    }

    /**
     * date加amount年
     *
     * @param date   目标日期
     * @param amount 增加年数
     * @return 计算后日期
     */
    public static Date addYears(Date date, int amount) {
        return org.apache.commons.lang.time.DateUtils.addYears(date, amount);
    }

    /*
     * 将时间转换为时间戳
     */
    public static Long dateToStamp(String s) {
        Date date = string2Date(s, DF_YYYY_MM_DD);
        if (date != null) {
            return date.getTime();
        } else {
            return null;
        }
    }
}
